package com.wnxy.sdd.controller;

import com.wnxy.sdd.common.constant.RedisCommon;
import com.wnxy.sdd.common.result.Result;
import com.wnxy.sdd.entity.Trainer;
import com.wnxy.sdd.log.OperatorType;
import com.wnxy.sdd.log.SystemLog;
import com.wnxy.sdd.model.query.TrainerQuery;
import com.wnxy.sdd.model.vo.PageVo;
import com.wnxy.sdd.service.ITrainerService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/trainer")
@Api(tags = "培训师管理")
// 解决跨域问题的注解
//@CrossOrigin(origins = "http://localhost:8080")
//origins表示只允许指定的地址；默认运行所有来源
//@CrossOrigin
public class TrainerController {
    /**
     * 依赖注入：
     * 1、通过@Autowired注入
     * 2、通过构造器注入
     *   public TrainerController(ITrainerService trainerService) {}
     *   创建对象时候，通过spring自动装配，去ioc容器中找ITrainerService类型的对象注入；
     *   如果该类型的对象有多个，根据方法形参名称，去容器找对应的对象注入。
     */
    private final ITrainerService trainerService;
    private final RedisTemplate redisTemplate;
    private final StringRedisTemplate stringRedisTemplate;
    public TrainerController(
            ITrainerService trainerService,
            StringRedisTemplate stringRedisTemplate,
            RedisTemplate redisTemplate) {
        this.trainerService = trainerService;
        this.redisTemplate = redisTemplate;
        this.stringRedisTemplate = stringRedisTemplate;

    }

    /**
     * 根据id查询
     * @Cacheable缓存注解
     * 1、修饰在方法上，会把方法返回的结果放入环境
     * 2、执行流程：先根据key从缓存中获取数据，如果获取到直接返回，不执行方法；
     * 如果没有获取到，执行方法并把方法返回的结果放入缓存
     * 3、属性
     *      value   指定缓存的名称，会作为redis缓存key的一部分
     *      key     缓存的key，
     *              #id 表示获取方法的id参数名称对应的值作为key
     * 4、注意：
     * 4.1、Spring提供的缓存注解要生效，必须要手动开启：@EnableCaching
     * 4.2、要求方法返回的对象要实现可序列化接口
     *      Result、Trainer 都要实现可序列化接口
     */
    @SystemLog(value = "根据id查询",type = OperatorType.QUERY)
    @GetMapping("/{id}")
    @ApiOperation("根据id查询")
    @Cacheable(value = "trainer:find",key = "#id")
    public Result findById(@PathVariable("id") String id){
        Trainer trainer = trainerService.getById(id);
        return Result.ok(trainer);
    }

    /**
     * 根据id删除数据库数据，同时删除缓存数据
     * @CacheEvict:
     * 1、用于清除缓存中的数据。可以设置清除的条件、清除的 key 值等。
     * 2、allEntries = true 表示删除value名称下的所有缓存
     * 3、先执行方法后，再删除缓存
     */
    @DeleteMapping("/{id}")
    @ApiOperation("删除")
    @CacheEvict(value = "trainer:find",key = "#id")
    public Result deleteById(@PathVariable("id") String id){
        trainerService.removeById(id);
        return Result.ok();
    }

    /**
     * 添加或修改,数据库数据改变，就清空缓存
     */
    @PutMapping
    @ApiOperation("添加或修改")
    @CacheEvict(value = "trainer:find",key = "#trainer.id")
    public Result saveOrUpdate(@RequestBody Trainer trainer){
        trainerService.saveOrUpdate(trainer);

        // 无效图片删除：通过set集合存储保存到数据库的图片，有效图片
        String avatar = trainer.getAvatar();
        if (StringUtils.hasText(avatar)) {
            // 获取文件名
            String fileName = avatar.substring(avatar.lastIndexOf("/") + 1);
            // 保存到redis的set集合
            stringRedisTemplate.opsForSet().add(RedisCommon.DB_IMAGE,fileName);
        }
        return Result.ok();
    }

    /**
     * 批量删除; 也需要删除缓存数据
     * 需求：ids = ["1669267666838032385","1669267706470010881"]
     * 缓存数据：
     *    trainer:find::1669267666838032385
     *    trainer:find::1669267706470010881
     */
    @PostMapping("/del/batch")
    @ApiOperation("批量删除")
    public Result delBatch(@RequestBody List<String> ids){
        boolean flag = trainerService.removeBatchByIds(ids);
        if (flag) {
            // 遍历集合，拼接缓存key
            List<String> keyList = ids.stream().map(id -> "trainer:find::" + id)
                    .collect(Collectors.toList());
            // 删除缓存
            redisTemplate.delete(keyList);
        }
        return Result.ok();
    }

    /**
     * 查询全部
     */
    @GetMapping
    @ApiOperation("查询全部")
    public Result<List<Trainer>> findAll(){
        List<Trainer> list = trainerService.list();
        return Result.ok(list);
    }


    /**
     * 分页查询
     */
    @PostMapping("/page/{current}/{size}")
    @ApiOperation("分页查询")
    public Result findByPage(
            @PathVariable("current") Integer current,
            @PathVariable("size") Integer size,
            @RequestBody TrainerQuery trainerQuery){
        PageVo<Trainer> page = trainerService.findByPage(current,size,trainerQuery);
        return Result.ok(page);
    }

}
